<html>
  <head>
    <title>存储库</title>
  </head>
  <body>
    <script>
        //  存储库  最佳实践和约定

                //  本文档提供了基于Domain-Driven-Design原则在模块和应用程序中实现存储库类的最佳实践。
                
                /*
                    一、存储接口

                            在域层中定义存储库接口。

                            定义一个存储库接口（如IIdentityUserRepository）并为每个聚合根创建其相应的实现。

                                  ①、始终使用应用程序代码中创建的存储库接口。

                                  ②、不要在应用程序代码中使用通用存储库接口（如IRepository<IdentityUser, Guid>）。

                                  ③、不要在应用程序代码（域、应用程序…层）中使用IQueryable<TEntity>功能。



                              eg：  有一个如下聚合根：

                                    public class IdentityUser : AggregateRoot<Guid>
                                    {
                                        //...
                                    }



                              eg: 定义存储库接口如下：

                                    public interface IIdentityUserRepository : IBasicRepository<IdentityUser, Guid>
                                    {
                                        //...
                                    }

                                注意： 

                                      ①、不要从IRepository<TEntity, TKey>接口继承存储库接口。
                                      
                                        因为它继承了IQueryable并且存储库不应该向应用程序公开IQueryable。

                                      ②、从IBasicRepository<TEntity, TKey>继承存储库接口（通常）或功能较低的接口，
                                        
                                        如IReadOnlyRepository<TEntity, TKey>（如果需要）。

                                      ③、不要为不是聚合根的实体定义存储库。

                */

                /*
                    二、存储库方法

                         ①、 将所有的存储库方法定义为异步。

                         ②、 向每个存储库方法添加可选的 cancellationToken参数。

                                eg：
                                      Task<IdentityUser> FindByNormalizedUserNameAsync(
                                          [NotNull] string normalizedUserName,
                                          CancellationToken cancellationToken = default
                                      );      
                                      
                         ③、请为每个返回"单个实体"的存储库方法添加一个可选的  bool includeDetails = true参数(默认值为 true)

                                eg:  
                                       Task<IdentityUser> FindByNormalizedUserNameAsync(
                                            [NotNull] string normalizedUserName,
                                            bool includeDetails = true,
                                            CancellationToken cancellationToken = default
                                        ); 

                                此参数是为ORM实现的，标识是否急切加载实体的导航属性。

                          ④、不要试图创建一个复合类来组合实体，(一个方法获取多个实体类型的实体)。
                          
                                相反，正确使用includeDetails选项在需要时添加实体的所有详细信息。
                              
                */
    </script>
  </body>
</html>